//
//  NordicUpgradeVC.swift
//  SDKDebuggingDemo
//
//  Created by 秦晟哲 on 2019/7/30.
//  Copyright © 2019 QinszQSZ. All rights reserved.
//

import UIKit
import iOSDFULibrary
import CoreBluetooth

class NordicUpgradeVC: UIViewController,LoggerDelegate,DFUServiceDelegate,DFUProgressDelegate,CBCentralManagerDelegate {

    
    @IBOutlet weak var deviceInfoView: UITextView!
    @IBOutlet weak var upgradePackInfoView: UITextView!
    @IBOutlet weak var processView: UITextView!
    
    let bleShell = KCTSingleBLEShell.sharedInstance
    
    var deviceInfos:(identifier:String,macStr:String,dfuMacStr:String,firmware:KCTFirmwareInfos)?
    
    var upgradePackInfo:(adaptNum:Int,fileName:String,file:Data)?
    
    var isInDFUMode = false
    
    var progress:Int = -1
    
    var searchDFUDeviceTimer:Timer?
    var connectDFUDeviceTimer:Timer?
    
    let dfuSearchManager = CBCentralManager.init()
    var dfuPeripheral:CBPeripheral?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dfuSearchManager.delegate = self
        
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    @IBAction func clickBack(_ sender: Any) {
        self.navigationController?.popViewController(animated: true)
    }
    
    @IBAction func clickToDFU(_ sender: Any) {
        
        let vc = DFUStatusUpgradeVC.init(nibName: "DFUStatusUpgradeVC", bundle: Bundle.main)
        self.navigationController?.pushViewController(vc, animated: true)
        
    }
    
    
    /// 点击获取设备信息
    @IBAction func clickReqDeviceInfo(_ sender: Any) {
        
        self.deviceInfos = nil
        self.deviceInfoView.text = nil
        
        if bleShell.isShakedHands == false {
            SVProgressHUD.showInfo(withStatus: "蓝牙没有连接")
            return
        }
        
        
        self.reqMac(identifier: bleShell.currentPeripheral!.identifier.uuidString)
    }
    
    // 获取mac地址
    func reqMac(identifier:String) {
        SVProgressHUD.show(withStatus: "获取Mac地址...")
        let task = KCTOldBLETaskReadProfile.init {[weak self] (tsk, profile, error) -> (Void) in
            if let err = error {
                let errDes = "获取Mac地址失败:\(err)"
                SVProgressHUD.showError(withStatus: errDes)
                self?.deviceInfoView.text = errDes
            }else{
                self?.reqFirmwareInfo(identifier: identifier, macStr: profile!.macString)
            }
        }
        bleShell.resume(baseTask: task)
        
    }
    
    // 获取固件信息
    func reqFirmwareInfo(identifier:String,macStr:String) {
        
        if let error = _checkDevMatching(identifier: identifier) {
            self.deviceInfoView.text = error.description
            SVProgressHUD.showInfo(withStatus: error)
            return
        }
        
        SVProgressHUD.show(withStatus: "获取固件信息...")
        let task = KCTOldBLETaskReadFirmwareInfos.init {[weak self] (tsk, error, infos) in
            if let err = error {
                let errDes = "获取固件信息失败:\(err)"
                SVProgressHUD.showError(withStatus: errDes)
                self?.deviceInfoView.text = errDes
            }else{
                SVProgressHUD.dismiss()
                let dfuMacStr = DFUMacString(macString: macStr)
                let devInfos = (identifier,macStr,dfuMacStr ?? "计算失败",infos!)
                self?.deviceInfos = devInfos
                // 记录固件序列号，以供升级途中失败后，重连进行升级
                if let dfuMac = dfuMacStr {
                    UserDefaults.standard.set(devInfos.3.serialNumber, forKey: dfuMac)
                    UserDefaults.standard.synchronize()
                }
                let content = "identifier:\(devInfos.0)\nmac:\(devInfos.1)\ndfuMac:\(devInfos.2)\ninfos:platform=\(devInfos.3.platform),adaptNum=\(devInfos.3.serialNumber),version=\(devInfos.3.appVersion)"
                
                self?.deviceInfoView.text = content
            }
        }
        bleShell.resume(baseTask: task)
    }
    
    
    /// 点击获取固件包
    @IBAction func clickReqUpgradePack(_ sender: Any) {
        
        self.upgradePackInfo = nil
        self.upgradePackInfoView.text = nil
        
        guard let infos = self.deviceInfos else {
            self.upgradePackInfoView.text = "缺少设备信息"
            SVProgressHUD.showInfo(withStatus: "缺少设备信息")
            return
        }
        
        SVProgressHUD.show(withStatus: "从网络获版本信息")
        
        let adaptNum = infos.firmware.serialNumber
        
        let netTask = KCTHTTPSession.share.FirmwareInfoTask(fromProduct: false, appKey: TestAPPKey, secretKey: TestSecretKey, adaptiveNum: adaptNum) {[weak self] (versionInfos, error) in
            
            DispatchQueue.main.async {
                if let err = error {
                    IPrint("\(err)\n")
                    self?.upgradePackInfoView.text = "\(err)"
                    SVProgressHUD.showError(withStatus: err.description)
                    return
                }
                
                
                
                guard let `versionInfos` = versionInfos else {
                    SVProgressHUD.dismiss()
                    self?.upgradePackInfoView.text = "线上没有固件升级包信息"
                    return
                }
                
                // 获取升级文件
                guard let fileURL = URL.init(string: versionInfos.file) else{
                    SVProgressHUD.dismiss()
                    self?.upgradePackInfoView.text = "初始化地址固件文件URL失败,rawURLString = '\(versionInfos.file)'"
                    return
                }
                                
                SVProgressHUD.show(withStatus: "从网络获取升级文件")
                let fileTask = URLSession.shared.dataTask(with: fileURL) {[weak self] (data, response, error) in
                    DispatchQueue.main.async {
                        
                        SVProgressHUD.dismiss()
                        
                        if let err = error {
                            self?.upgradePackInfoView.text = "获取升级文件失败,error = '\(err)'"
                            return
                        }
                        
                        guard let fileData = data else {
                            self?.upgradePackInfoView.text = "获取升级文件失败,file长度为空"
                            return
                        }
                        
                        let packInfo = (adaptNum,response?.suggestedFilename ?? "",fileData)
                        let content = "\(versionInfos.yy_modelToJSONObject() ?? "")"
                        self?.upgradePackInfoView.text = content
                        self?.upgradePackInfo = packInfo
                    }
                }
                fileTask.resume()
                
                
            }
            
        }
        netTask?.resume()
    }    
    
    func _checkDevMatching(identifier:String) -> String?{
        
        if bleShell.isShakedHands == false{
            return "蓝牙未连接"
        }
        
        if let id = bleShell.currentPeripheral?.identifier.uuidString,id != identifier{
            return "当前连接设备发生了变化"
        }
        return nil
    }
    
    @IBAction func clickStartUpgrade(_ sender: Any) {
        
        // 判断准备工作是否完成
        
        guard let devInfos = self.deviceInfos else{
            self.deviceInfoView.text = nil
            SVProgressHUD.showInfo(withStatus: "缺少设备信息")
            return
        }
        
        guard let packInfo = self.upgradePackInfo else {
            self.upgradePackInfoView.text = nil
            SVProgressHUD.showInfo(withStatus: "缺少升级固件包")
            return
        }
        
        if bleShell.isShakedHands == false {
            SVProgressHUD.showInfo(withStatus: "蓝牙没有握手")
            return
        }
        
        if devInfos.firmware.platform != 0 {
            SVProgressHUD.showInfo(withStatus: "当前设备不是nordic平台")
            return
        }
        
        let currentId = bleShell.currentPeripheral!.identifier.uuidString
        
        if currentId != devInfos.identifier {
            SVProgressHUD.showInfo(withStatus: "identifier与当前设备不匹配")
            return
        }
        
        if devInfos.firmware.serialNumber != packInfo.adaptNum {
            SVProgressHUD.showInfo(withStatus: "固件信息序列号(\(devInfos.firmware.serialNumber))与固件包序列号(\(packInfo.adaptNum))不匹配")
            return
        }
        
        // 开始升级流程
        IPrint("准备工作完成，开始DFU升级")
        
        self.startFirmwareUpdate()
    }
    
    func startFirmwareUpdate() {
        self.dfuPeripheral = nil
        self.progress = -1
        SVProgressHUD.show(withStatus: "启动升级...")
        let startTask = KCTOldBLETaskFirmwareUpdate.init(dialogHeadData: nil) {[weak self] (tsk, error, success) in
            
            guard let `self` = self else{
                return
            }
            
            //error为空则认为成功
            if let err = error {
                SVProgressHUD.showError(withStatus: "启动升级失败")
                self.processView.text = "启动升级失败:" + err.description
                self.isInDFUMode = false
            }else{
                self.isInDFUMode = true
                //开始搜索dfu模式下的设备
                if self.dfuSearchManager.state == .poweredOn {
                    SVProgressHUD.show(withStatus: "搜索dfu设备")
                    self.startDFUSearchTimer()
                    self.dfuSearchManager.scanForPeripherals(withServices: nil, options: nil)
                }else{
                    SVProgressHUD.dismiss()
                    self.processView.text = "DFU搜索器还没准备好"
                }
            }
        }
        bleShell.resume(baseTask: startTask)
    }
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            // 准备就绪
            IPrint("✅dfuSearchManager准备就绪")
        }
    }
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        if isInDFUMode == false{
            return
        }
        guard let dfuMac = deviceInfos?.dfuMacStr else {
            return
        }

        if upgradePackInfo?.file == nil {
            return
        }
        
        guard let name = peripheral.name else {
            return
        }
        
        if name.lowercased().contains("dfutarg") == false {
            return
        }
        
        // 解析Mac地址
        guard let macAddr = KCTMacAddrParser.Parse(adData: advertisementData) else {
            return
        }
        
        if macAddr == dfuMac{
            // 找到目标DFU设备。
            central.stopScan()
            self.stopDFUSearchTimer()
            // 建立连接
            self.dfuPeripheral = peripheral
            self.startDFUConnectTimer()
            SVProgressHUD.show(withStatus: "正在连接DFU设备...")
            central.connect(peripheral, options: nil)
        }
    }
    
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        
        guard let targetPer = self.dfuPeripheral else {
            return
        }
        
        if targetPer === peripheral {
            // 连接失败
            IPrint("❌连接DFU设备失败,name:'\(peripheral.name ?? "")';mac:'\(peripheral.macString ?? "")'")
            self.stopDFUConnectTimer()
            SVProgressHUD.dismiss()
        }else{
            IPrint("⚠️其它DFU设备连接失败")
        }
    }
    
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        
        guard let targetPer = self.dfuPeripheral else {
            IPrint("⚠️当前没有目标DFU外设，准备断开链接")
            central.cancelPeripheralConnection(peripheral)
            return
        }
        
        if targetPer != peripheral {
            IPrint("⚠️其它DFU设备连接成功，准备断开链接")
            central.cancelPeripheralConnection(peripheral)
            return
        }
        
        // 连接dfu设备成功。
        self.stopDFUConnectTimer()
        
        guard let file = upgradePackInfo?.file else{
            SVProgressHUD.dismiss()
            return
        }
        
        let selectedFirmware = DFUFirmware.init(zipFile: file)
        
        if let firmware = selectedFirmware {
            SVProgressHUD.show(withStatus: "正在升级...")
            let queue = DispatchQueue.global()

            var initialtor = DFUServiceInitiator.init(queue: queue)
            initialtor = initialtor.with(firmware: firmware)
            initialtor.logger = self
            initialtor.delegate = self
            initialtor.progressDelegate = self
            
            let _ = initialtor.start(target: peripheral)
        }else{
            SVProgressHUD.dismiss()
            let message = "创建DFUFirmware失败"
            SVProgressHUD.showError(withStatus: message)
            self.processView.text = message
        }
    }
        
    func startDFUSearchTimer() {
        self.searchDFUDeviceTimer?.invalidate()
        let timer = Timer.init(timeInterval: 20.0, target: self, selector: #selector(searchDFUDeviceTimeout), userInfo: nil, repeats: false)
        self.searchDFUDeviceTimer = timer
        RunLoop.main.add(timer, forMode: .default)
    }
    
    func stopDFUSearchTimer()  {
        self.searchDFUDeviceTimer?.invalidate()
        self.searchDFUDeviceTimer = nil
    }
    
    /// 搜索DFU设备的超时处理
    @objc func searchDFUDeviceTimeout(){
        if let timer = self.searchDFUDeviceTimer {
            timer.invalidate()
        }
        self.searchDFUDeviceTimer = nil
        self.dfuSearchManager.stopScan()
        self.dfuPeripheral = nil
        self.isInDFUMode = false
        SVProgressHUD.showError(withStatus: "搜索DFU设备超时")
        self.processView.text = "搜索DFU设备超时"
    }
    
    func startDFUConnectTimer() {
        self.connectDFUDeviceTimer?.invalidate()
        let timer = Timer.init(timeInterval: 20.0, target: self, selector: #selector(connectDFUTimeout), userInfo: nil, repeats: false)
        self.connectDFUDeviceTimer = timer
        RunLoop.main.add(timer, forMode: .default)
    }
    
    func stopDFUConnectTimer() {
        self.connectDFUDeviceTimer?.invalidate()
        self.connectDFUDeviceTimer = nil
    }
    
    @objc func connectDFUTimeout() {
        self.stopDFUConnectTimer()
        self.dfuSearchManager.stopScan()
        self.dfuPeripheral = nil
        self.isInDFUMode = false
        SVProgressHUD.showError(withStatus: "搜索DFU设备超时")
        self.processView.text = "搜索DFU设备超时"
    }
    
    
    // MARK:- DFU代理
    func logWith(_ level: LogLevel, message: String) {
        IPrint("DFULog:leval=\(level),message=\(message)\n")
    }
    // MARK:- DFU代理
    func dfuStateDidChange(to state: DFUState) {
        if state == .disconnecting {

            if progress >= 100 {
                IPrint("固件升级成功!!!\n")
                SVProgressHUD.showSuccess(withStatus: "升级成功")
                self.processView.text = "升级成功"
            }else{
                IPrint("固件升级失败:dfu状态改变为\(state)")
                SVProgressHUD.showSuccess(withStatus: "固件升级失败:dfu状态改变为\(state)")
                self.processView.text = "固件升级失败:dfu状态改变为\(state)"
                progress = -1
            }
        }
    }
    // MARK:- DFU代理
    func dfuError(_ error: DFUError, didOccurWithMessage message: String) {
        IPrint("固件升级失败:error=\(error),\(message)\n")
        SVProgressHUD.showError(withStatus: "升级失败")
        progress = -1
    }
    // MARK:- DFU代理
    func dfuProgressDidChange(for part: Int, outOf totalParts: Int, to progress: Int, currentSpeedBytesPerSecond: Double, avgSpeedBytesPerSecond: Double) {
        self.progress = progress
        IPrint("升级进度:\npatr=\(part)\ntotalPart=\(totalParts)\nprogress=\(progress)%\ncurrentSpeed=\(currentSpeedBytesPerSecond)bit/s\navSpeed=\(avgSpeedBytesPerSecond)bit/s\n")
        self.processView.text = "升级进度:\npatr=\(part)\ntotalPart=\(totalParts)\nprogress=\(progress)%\ncurrentSpeed=\(currentSpeedBytesPerSecond)bit/s\navSpeed=\(avgSpeedBytesPerSecond)bit/s\n"
        SVProgressHUD.show(withStatus: "\(progress)%")
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    
}
